﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
using System.Reflection;
using Microsoft.Office.Interop.Outlook;
using System.Globalization;

namespace OutlookTags
{
    public class TagsController
    {
        const string ArchiveFolderName = "Archive";

        public Outlook.Application Application { get; private set; }
        Outlook.Explorer Explorer { get; set; }
        IList<ITagsView> Views { get; set; }
        
        public TagsController(Outlook.Application application)
        {
            Application = application;
            Explorer = Application.ActiveExplorer();
            Views = new List<ITagsView>();            

            WrapExplorer(application.ActiveExplorer());

            //TODO: start indexing
            UpdateFullTagList();
        }

        public void AttachView(ITagsView view)
        {
            view.Initialize(this);
            Views.Add(view);
            UpdateFullTagList();
        }

        public void ArchiveSelection()
        {
            Outlook.Folder archive = FindOrCreateArchiveFolder();

            foreach (var item in Explorer.Selection)
            {
                //TODO: create mail item enumerator
                MailItem mail = (MailItem)item;
                if (mail != null)
                {                    
                    mail.UnRead = false;
                    mail.Move(archive);
                    mail.Save();
                }
            }
        }

        private Outlook.Folder FindOrCreateArchiveFolder()
        {
            Outlook.Folder mailBoxFolder = (Outlook.Folder)Application.Session.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox).Parent;
            Outlook.Folder archive = null;
            foreach (Outlook.Folder folder in mailBoxFolder.Folders)
            {
                if (folder.Name == ArchiveFolderName)
                {
                    archive = folder;
                    break;
                }                
            }

            if (archive == null)
            {
                archive = (Outlook.Folder)mailBoxFolder.Folders.Add(ArchiveFolderName, Missing.Value);                
            }

            return archive;

        }


        private void WrapExplorer(Microsoft.Office.Interop.Outlook.Explorer explorer)
        {
            explorer.SelectionChange += new Microsoft.Office.Interop.Outlook.ExplorerEvents_10_SelectionChangeEventHandler(explorer_SelectionChange);
            explorer.FolderSwitch += new ExplorerEvents_10_FolderSwitchEventHandler(explorer_FolderSwitch);
        }

        void explorer_FolderSwitch()
        {
            var archive = FindOrCreateArchiveFolder();
            foreach (var view in Views)
            {
                view.SetArchiveEnabled(archive.FullFolderPath != Explorer.CurrentFolder.FullFolderPath);
            }
        }

        private void explorer_SelectionChange()
        {
            var tags = GetTagsListFromSelection();
            foreach (var view in Views)
            {
                view.UpdateSelection(tags);
            }
        }

        private IList<DisplayTag> GetTagsListFromSelection()
        {
            var separator = CultureInfo.CurrentCulture.TextInfo.ListSeparator.ToCharArray();
            List<DisplayTag> res = new List<DisplayTag>();
            List<string[]> tagsArrays = new List<string[]>();
            foreach (var item in Explorer.Selection)
            {
                Outlook.MailItem mail = (Outlook.MailItem)item;
                if (mail != null)
                {
                    if (mail.Categories != null)
                        tagsArrays.Add(mail.Categories.Split(separator).Select(s => s.Trim()).ToArray());
                    else
                        tagsArrays.Add(new string[] { });
                }
            }

            if (tagsArrays.Count == 1)
            {
                return tagsArrays[0].Select(t => new DisplayTag() { Name = t }).ToList();
            }
            else if (tagsArrays.Count > 1)
            { 
            }

            return res;
        }

        private void UpdateFullTagList()
        {
            List<DisplayTag> tags = new List<DisplayTag>();
            foreach (Outlook.Category category in Explorer.Session.Categories)
            {
                tags.Add(new DisplayTag(){Name = category.Name});
            }

            foreach (var view in Views)
            {
                view.UpdateDisplayTags(tags);
            }
        }

        public void ApplyTagsForCurrentItem(string tags)
        {
            string categories = ConvertTagsToCategories(tags);
            foreach (var item in Explorer.Selection)
            {
                Outlook.MailItem mail = (Outlook.MailItem)item;
                if (mail != null)
                {
                    mail.Categories = categories;
                    mail.Save();
                }
            }
        }

        private string ConvertTagsToCategories(string tagsString)
        {
            var separator = CultureInfo.CurrentCulture.TextInfo.ListSeparator.ToCharArray();
            string[] tags = tagsString.Split(separator);
            Dictionary<string, Outlook.Category> categories = new Dictionary<string, Microsoft.Office.Interop.Outlook.Category>();
            foreach (Outlook.Category item in Application.Session.Categories)
            {
                categories[item.Name.ToUpper()] = item;
            }
            //TODO: fix bug if add 2 or more new but identical categories i.e tag1;tag1;tag1
            List<string> notExistsCategories = new List<string>();
            foreach (var tag in tags)
            {
                var trimedTag = tag.Trim();
                if (trimedTag.Length > 0)
                {
                    if (!categories.ContainsKey(trimedTag.ToUpper()))
                    {
                        notExistsCategories.Add(trimedTag);
                        Application.Session.Categories.Add(trimedTag, Outlook.OlColor.olAutoColor, Missing.Value);
                    }
                }
            }

            UpdateFullTagList();

            return tagsString;
        }

        public void SearchTag(string[] tags)
        {
            StringBuilder query = new StringBuilder();
            foreach (var tag in tags)
            {
                query.AppendFormat(" category:=\"{0}\"", tag);
            }
            Explorer.Search(query.ToString(), OlSearchScope.olSearchScopeAllFolders);
        }
    }
}
